package org.mm.proxycache.http.codec;

import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Map;

import org.apache.mina.common.IoBuffer;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.mm.proxycache.http.HttpChunk;
import org.mm.proxycache.http.HttpMessage;

public abstract class HttpEncoder extends ProtocolEncoderAdapter
{

    void encodeChunk( HttpChunk chunk, ProtocolEncoderOutput out ) throws CharacterCodingException
    {
        if ( chunk.isLast() )
        {
            if ( chunk.message().isChunked() )
            {
                IoBuffer buf = IoBuffer.allocate( 5 );
                buf.put( (byte) '0' );
                buf.put( CRLF );
                buf.put( CRLF );
                buf.flip();

                out.write( buf );
            }
            out.flush();
            return;
        }

        IoBuffer data = IoBuffer.wrap( chunk.data().array(), chunk.data().arrayOffset()
                + chunk.data().position(), chunk.data().remaining() );

        if ( chunk.message().isChunked() )
        {

            IoBuffer buf = IoBuffer.allocate( 10, false );
            buf.setAutoExpand( true );
            buf.putString( Integer.toHexString( chunk.size() ), charsetEncoder );
            buf.put( CRLF );
            buf.flip();

            out.write( buf );
            out.write( data );

            IoBuffer b2 = IoBuffer.allocate( 2 );
            b2.put( CRLF );
            b2.flip();
            out.write( b2 );
        }
        else
        {
            out.write( data );
        }
    }

    void encode( HttpMessage msg, IoBuffer out ) throws CharacterCodingException
    {
        out.put( CRLF );
        for ( Map.Entry<String, String> entry : msg.getHeaders().entries() )
        {
            out.putString( entry.getKey(), charsetEncoder );
            out.put( Separator );
            out.putString( entry.getValue(), charsetEncoder );
            out.put( CRLF );
        }

        out.put( CRLF );
    }

    private static byte CRLF[] = { '\r', '\n' };
    private static byte Separator[] = { ':', ' ' };

    private final static Charset charset = Charset.forName( "US-ASCII" );
    protected final CharsetEncoder charsetEncoder = charset.newEncoder();
}
